/*
 * DWarteschlange.java
 * 
 *  author: Daniel Rudigier
 *    date: 23.05.2008
 * 
 * 
 */
package ocumed.domaene.behandlung;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import ocumed.teams.IArzt;
import ocumed.teams.IPatient;
import ocumed.teams.IWarteposition;
import ocumed.teams.IWarteschlange;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * domain functionality for a patient queue
 * 
 * @author Daniel Rudigier
 *
 */
public class DWarteschlange implements IWarteschlange {
    private static final Log log = LogFactory.getLog(DWarteschlange.class);
    
    private IArzt m_arzt;
    private TreeSet<IWarteposition> m_wartepositionen;
    private HashMap<Integer, IWarteposition> m_index;
    
    /**
     * 
     * constructor
     * 
     * @param a
     * @param w
     */
    public DWarteschlange(IArzt a, Set<IWarteposition> w) {
        m_arzt = a;
        m_index = new HashMap<Integer, IWarteposition>();
        setWartepositionen(w);
    }
    
    /**
     * override
     *
     * @see ocumed.teams.IWarteschlange#einreihen(ocumed.teams.IPatient)
     */
    public IWarteposition einreihen(IPatient p) {
        IWarteposition ret = null;
        
        // check if it is in the queue already
        if (m_index.get(p) == null) {
            short newpos = getNewPosition();
            ret = new DWarteposition(0, m_arzt, null, p, newpos);
            m_index.put(p.getPatientid(), ret);
        }
        
        return ret;
    }
   

    /**
     * override
     *
     * @see ocumed.teams.IWarteschlange#ausreihen(ocumed.teams.IPatient)
     */
    public IWarteposition ausreihen(IPatient p) {
        log.debug("remove position: " + p.getPatientid());
        log.debug("index size: " + m_index.size());
        
        IWarteposition o = m_index.get(p.getPatientid());
        if (o != null) {
            m_wartepositionen.remove(o);
        } else {
            log.debug("not found: " + p.getPatientid());
        }
        
        return o;
    }
    
    /**
     * override
     *
     * @see ocumed.teams.IWarteschlange#position(ocumed.teams.IPatient, boolean, boolean)
     */
    public IWarteposition[] position(IPatient p, boolean nachVorne, boolean maximal) {
        log.debug("new position for: " + p.getPatientid() + " q.s: " + m_wartepositionen.size());
        IWarteposition[] ret = null;
        
        // identify the positions
        IWarteposition first = m_wartepositionen.size() > 0 ? m_wartepositionen.first() : null;
        IWarteposition last = m_wartepositionen.size() > 0 ? m_wartepositionen.last() : null;
        IWarteposition previous = null;
        IWarteposition next = null;
        
        IWarteposition current = null;
        for (Iterator<IWarteposition> iterator = m_wartepositionen.iterator(); iterator.hasNext(); ) {
            previous = current;
            current = iterator.next();
            
            if (current.getPatient().getPatientid() == p.getPatientid()) {
                next = iterator.hasNext() ? iterator.next() : null;
                break;
            }
        }
        log.debug("identified positions");
        
        // reassign positions
        if (current != null) {
            IWarteposition target = null;
            if (nachVorne) {
                if (!maximal && previous != null) {
                    target = previous;
                } else if (maximal && first != null) {
                    target = first;
                }
            } else {
                if (!maximal && next != null) {
                    target = next;
                } else if (maximal && last != null) {
                    target = last;
                }
            }
            
            if (target != null) {
                log.debug("reassign and swap");
                swap(current, target);
                ret = new IWarteposition[] { current, target };
            } else {
                log.debug("nothing to do");
            }
        } else {
            log.debug("patient not found in queue: " + p.getPatientid());
            log.debug("this happens, if a patient is enqueued to a different doctor. (not supported yet)");
        }
        
        return ret;
    }
    
    /**
     * override
     *
     * @see ocumed.teams.IWarteschlange#getWartepositionen()
     */
    public TreeSet<IWarteposition> getWartepositionen() {
        return m_wartepositionen;
    }

    /**
     * @param wartepositions
     */
    public void setWartepositionen(Set<IWarteposition> wartepositions) {
        m_wartepositionen = new TreeSet<IWarteposition>();

        for (IWarteposition iw : wartepositions) {
            m_wartepositionen.add(iw);
            m_index.put(iw.getPatient().getPatientid(), iw);
        }
    }
    
    
    /**
     * swap and reassign the position
     * 
     * @param o1
     * @param o2
     */
    private void swap(IWarteposition o1, IWarteposition o2) {
        //log.debug("old: " + o1 + " <<>> " + o2);
        m_wartepositionen.remove(o1);
        m_wartepositionen.remove(o2);
        
        short tmp = o1.getWartepositionnr();
        o1.setWartepositionnr(o2.getWartepositionnr());
        o2.setWartepositionnr(tmp);
        
        log.debug("new: " + o1 + " <<>> " + o2);
        m_wartepositionen.add(o1);
        m_wartepositionen.add(o2);
    }

    
    /**
     * get a new position for a new patient (latest)
     * 
     * @return
     */
    private short getNewPosition() {
        short max = 0;
        for(IWarteposition w : m_index.values()) {
            if (w.getWartepositionnr() > max) {
                max = w.getWartepositionnr();
            }
        }
        String val = (max + 1) + ""; // some very nice trick
        return Short.valueOf(val);
    }
    
    /**
     * override
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuffer b = new StringBuffer();
        for (IWarteposition w : m_wartepositionen) {
            b.append(w.getPatient().getPatientid() + ",");
        }
        return b.toString();
    }
}
